#include "xworker.h"

#include "xworker_single_queue.h"
#include "xworker_double_queue.h"
#include "xworker_priority_queue.h"

namespace xge{
namespace xge_internal{


  class VirtualWorker::WorkerThread : public ThreadDelegate {
  public:
    virtual void ThreadMain() {
      queue_->Loop();
    }

    WorkerThread( const WorkerQueuePtr& ptr ) : queue_(ptr){}

    void set_queue_type( const WorkerQueuePtr& ptr ) {
      queue_ = ptr;
    }

    void Clear() {
      queue_.Reset();
    }

    bool Empty() const {
      return queue_.Null();
    }

  private:
    WorkerQueuePtr queue_;
  };


  bool VirtualWorker::Dispatch( const int worker_type , const String& thread_name , const char* debug_name ) {
    // doing the dispatching of the target worker 
    XASSERT( thread_handler_ptr_.Null() );
    // Establish the queue type 
    WorkerQueue* raw_queue ;
    switch( worker_type ){
    case WorkerQueue::QUEUE_TYPE_SINGLE_QUEUE:
      raw_queue = new WorkerSingleQueue();
      break;
    case WorkerQueue::QUEUE_TYPE_DOUBLE_QUEUE:
      raw_queue = new WorkerDoubleQueue();
      break;
    case WorkerQueue::QUEUE_TYPE_PRIROITY_QUEUE:
      raw_queue = new WorkerPriorityQueue();
      break;
    default: 
      // error
      return false;
    }
    worker_queue_ptr_.Reset(raw_queue);
    // Setting the thread stuff 
    // 1. Initialize the thread delegate stuff 
    if( thread_delegate_ptr_.Null() )
      thread_delegate_ptr_.Reset( new WorkerThread(worker_queue_ptr_) );
    else {
      WorkerThread* wthread = (WorkerThread*)thread_delegate_ptr_.Get();
      wthread->set_queue_type( worker_queue_ptr_ );
    }
    // 2. Initialize the thread handler stuff
    thread_handler_ptr_ = ThreadManager::CreateXThread(
      NULL,thread_delegate_ptr_,thread_name,debug_name,true );
    if( thread_handler_ptr_.Null() ) {
      // thread can not be set up now .
      worker_queue_ptr_.Reset();
      return false;
    }
    return true;
  }

  bool VirtualWorker::Destroy( bool post_quit_soon , bool blocking ) {
    XASSERT( !thread_handler_ptr_.Null() );
    has_post_destroy_request_ = true;
    if( post_quit_soon ) 
      worker_queue_ptr_->PostQuitSoon();
    else
      worker_queue_ptr_->PostQuitWhenEmpty();
    if( blocking ) {
      return Wait();
    } 
    return true;
  }

  const TripleResult VirtualWorker::Wait() {
    XASSERT( !thread_handler_ptr_.Null() );
    const TripleResult ret( thread_handler_ptr_->Join() );
    if( ret.operator bool() == false ) {
      thread_handler_ptr_.Reset();
      worker_queue_ptr_.Reset();
      has_post_destroy_request_ = false;
    }
    return ret;
  }

  const TripleResult VirtualWorker::Wait( size_t ms ) {
    XASSERT( !thread_handler_ptr_.Null() );
    const TripleResult ret( thread_handler_ptr_->Join(ms) );
    if( ret.operator bool() == false ) {
      thread_handler_ptr_.Reset();
      worker_queue_ptr_.Reset();
      has_post_destroy_request_ = false;
    }
    return ret;
  }

  void VirtualWorker::PushTask( const TaskPtr& task , bool delay ) {
    XASSERT( !thread_handler_ptr_.Null() );
    // we do not check the task type since it will be checked
    // in the worker queue class or the upper class !
    if( !delay )
      worker_queue_ptr_->PushTask( task );
    else 
      task_cache_.push_back(task);

  }

  void VirtualWorker::Sync() {
    worker_queue_ptr_->PushTask(&task_cache_);
    task_cache_.clear();
  }

  VirtualWorker::~VirtualWorker() {
    if( !thread_handler_ptr_.Null() ) {
      Destroy(true,true);
      SYS_LOG(PANIC,true,_xT("A worker queue has not been turned off when the worker has been deleted!\n")
        _xT("ThreadName:%s.\n") , thread_handler_ptr_->name().c_str() );
    }
  }

}// namespace xge_internal
}// namespace xge